home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / ax25cmd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-09-24  |  21.4 KB  |  1,023 lines

  1. /*
  2. ** FILE: ax25cmd.c
  3. **
  4. ** AX.25 command handler.
  5. **
  6. ** 09/24/90 Bob Applegate, wa2zzx
  7. **    Added BCTEXT, BC, and BCINTERVAL commands for broadcasting an id
  8. **    string using UI frames.
  9. */
  10.  
  11. #include <stdio.h>
  12. #include <time.h>
  13. #include "global.h"
  14. #include "config.h"
  15. #include "mbuf.h"
  16. #include "timer.h"
  17. #include "proc.h"
  18. #include "iface.h"
  19. #include "ax25.h"
  20. #include "cmdparse.h"
  21. #include "socket.h"
  22. #include "mailbox.h"
  23. #include "session.h"
  24. #include "tty.h"
  25. #include "nr4.h"
  26. #include "commands.h"
  27. #include "asy.h"
  28. #ifdef SCC
  29. #include "scc.h"
  30. #endif
  31. #ifdef DRSI
  32. #include "drsi.h"
  33. #endif
  34. #ifdef VANESSA
  35. #include "vanessa.h"
  36. #endif
  37.  
  38. #define next_seq(n)        (((n) + 1) & 7)
  39.  
  40. /* Defaults for IDing... */
  41. static char Axbctext[256];
  42. static struct timer Broadtimer;        /* timer for broadcasts */
  43.  
  44. int32 Axholdtime = AXROUTEHOLDTIME;
  45.  
  46. static struct iface * near cmp_if __ARGS((char *ifname));
  47. static void near ax_bc __ARGS((struct iface *axif));
  48. /* static int near axheard __ARGS((struct iface *ifp)); */
  49. static char  * near pathtostr __ARGS((struct ax25_cb *cp));
  50. static int doroutestat __ARGS((int  argc,char  *argv[],void *p));
  51.  
  52. char *Ax25states[] = {
  53.     "",
  54.     "Disconnected",
  55.     "Listen",
  56.     "Conn pending",
  57.     "Disc pending",
  58.     "Connected",
  59. };
  60.  
  61. char *Ax25reasons[] = {
  62.     "Normal",
  63.     "Reset",
  64.     "Timeout",
  65.     "Network",
  66. };
  67.  
  68. static struct iface * near
  69. cmp_if(char *ifname)
  70. {
  71.     struct iface *ifp;
  72.  
  73.     if((ifp = if_lookup(ifname)) == NULLIF) {
  74.         tprintf(Badif,ifname);
  75.         return NULLIF;
  76.     }
  77.     if(ifp->output != ax_output) {
  78.         tprintf(Badax,ifname);
  79.         return NULLIF;
  80.     }
  81.     return ifp;
  82. }
  83.  
  84. /* This is the low-level broadcast function. */
  85. static void near
  86. ax_bc(axif)
  87. struct iface *axif;
  88. {
  89.     /* prepare the header */
  90.     int i = strlen(Axbctext);
  91.     struct mbuf *hbp = ambufw(i);
  92.  
  93.     hbp->cnt = i;
  94.     memcpy(hbp->data,Axbctext,i);
  95.  
  96.     (*axif->output)(axif,Ax25multi[2],axif->hwaddr,PID_NO_L3,hbp);    /* send it */
  97. }
  98.  
  99. /* This function is called to send the current broadcast message
  100.  * and reset the timer. */
  101. static int
  102. dobc(argc,argv,p)
  103. int argc;
  104. char *argv[];
  105. void *p;
  106. {
  107.     struct iface *ifp;
  108.     int i;
  109.  
  110.     for(i = 1; i < argc; i++)
  111.         if((ifp = cmp_if(argv[i])) != NULLIF)
  112.             ax_bc(ifp);
  113.     return;
  114. }
  115.  
  116. /* View/Change the message we broadcast. */
  117. static int
  118. dobctext(argc,argv,p)
  119. int argc;
  120. char *argv[];
  121. void *p;
  122. {
  123.     int i;
  124.  
  125.     if (argc < 2 && Axbctext[0] != '\0') {
  126.             tprintf("%s\n",Axbctext);
  127.     } else {
  128.         Axbctext[0] = '\0';
  129.  
  130.         for (i = 1; i < argc; i++) {
  131.             strcat(Axbctext,argv[i]);
  132.             if(strlen(Axbctext) > 220)
  133.                 break;
  134.             strcat(Axbctext," ");
  135.         }
  136.         if(strlen(Axbctext) > 2) {
  137.             strcat(Axbctext,AX_EOL);
  138.             strcat(Axbctext,"\0");
  139.         } else
  140.             Axbctext[0] = '\0';
  141.     }
  142.     return 0;
  143. }
  144.  
  145. static void
  146. dobroadtick()
  147. {
  148.     struct iface *ifp;
  149.  
  150.     stop_timer(&Broadtimer);
  151.  
  152.     for(ifp = Ifaces; ifp; ifp = ifp->next)
  153.         if(ifp->output == ax_output)
  154.             ax_bc(ifp);
  155.  
  156.     /* Restart timer */
  157.     start_timer(&Broadtimer) ;
  158. }
  159.  
  160. /* Examine/change the broadcast interval. */
  161. static int
  162. dobcint(argc,argv,p)
  163. int argc;
  164. char *argv[];
  165. void *p;
  166. {
  167.     if(argc < 2) {
  168.         tprintf("ID timer %lu/%lu s\n",
  169.             read_timer(&Broadtimer)/1000L,
  170.             dur_timer(&Broadtimer)/1000L);
  171.     } else {
  172.         stop_timer(&Broadtimer) ;            /* in case it's already running */
  173.         /* what to call on timeout */
  174.         Broadtimer.func = (void (*) __ARGS((void *))) dobroadtick;
  175.         Broadtimer.arg = NULLCHAR;            /* dummy value */
  176.         /* set timer duration */
  177.         set_timer(&Broadtimer,atol(argv[1]) * 1000L);
  178.         start_timer(&Broadtimer);            /* and fire it up */
  179.     }
  180.     return 0;
  181. }
  182.  
  183. static int
  184. dobud(argc,argv,p)
  185. int argc;
  186. char *argv[];
  187. void *p;
  188. {
  189.     char tmp[AXBUF];
  190.  
  191.     setcall(tmp,argv[1]);
  192.     is_bud(tmp,1);
  193.     return 0;
  194. }
  195.  
  196. static int
  197. doaxclose(argc,argv,p)
  198. int argc;
  199. char *argv[];
  200. void *p;
  201. {
  202.     struct ax25_cb *axp = (struct ax25_cb *)ltop(htol(argv[1]));
  203.  
  204.     if(!ax25val(axp)){
  205.         tputs(Notval);
  206.         return 1;
  207.     }
  208.     return disc_ax25(axp);
  209. }
  210.  
  211. static int
  212. doaxreset(argc,argv,p)
  213. int argc;
  214. char *argv[];
  215. void *p;
  216. {
  217.     struct ax25_cb *axp = (struct ax25_cb *)ltop(htol(argv[1]));
  218.  
  219.     if(!ax25val(axp)){
  220.         tputs(Notval);
  221.         return 1;
  222.     }
  223.     return reset_ax25(axp);
  224. }
  225.  
  226. static int near
  227. axheard(ifp,tp)
  228. struct iface *ifp;
  229. char *tp;
  230. {
  231.     int j, pid;
  232.     char tmp[AXBUF], *cp;
  233.     struct lq *lp;
  234.     char type[8];   /* Type of traffic heard (TCP/IP, AX.25 etc) */
  235.  
  236.     if(ifp->hwaddr == NULLCHAR)
  237.         return 0;
  238.  
  239.     for(lp = ifp->lq, j = 0; j < ifp->Hcurrent; lp++, j++) {
  240.         if(j == 0) {
  241.             if(tp != NULLCHAR)
  242.             tprintf("Iface: %s\n%-12s%-28s%-11s%-15s\n",
  243.                 ifp->name,
  244.                     "Call",
  245.                     "Last Heard",
  246.                     "Traffic",
  247.                         "Packets");
  248.         }
  249.         pid = (int)lp->pid;
  250.         cp = ctime(&lp->time);
  251.         cp[24] = '\0';
  252.  
  253.             if (pid == PID_IP)
  254.                     strcpy(type, "TCP/IP");
  255.             else if (pid == PID_ARP)
  256.                     strcpy(type, "ARP");
  257.             else if (pid == PID_TEXNET)
  258.                     strcpy(type, "TexNet");
  259.             else if (pid == PID_X25)
  260.                     strcpy(type, "X.25");
  261.             else if (pid == PID_SEGMENT)
  262.                     strcpy(type, "SegFrag");
  263.             else if (pid == PID_FLEXNET)
  264.                     strcpy(type, "FlexNet");
  265.             else if (pid == PID_NETROM)
  266.                     strcpy(type, "NET/ROM");
  267.             else if (pid == PID_NO_L3)
  268.                     strcpy(type, "IP/CAM");
  269.             else
  270.                     strcpy(type, "AX.25");
  271.  
  272.         tprintf("%-12s%-28s%-11s%-15ld\n",pax25(tmp,lp->addr),
  273.                                                  cp,type,lp->currxcnt);
  274.  
  275.     }
  276.     return 0;
  277. }
  278.  
  279. int
  280. doaxheard(argc,argv,p)
  281. int argc;
  282. char *argv[];
  283. void *p;
  284. {
  285.     struct iface *ifp;
  286.  
  287.     tprintf("System time: %s",ctime(&currtime));
  288.  
  289.     if(argc > 1){
  290.         if((ifp = cmp_if(argv[1])) != NULLIF)
  291.             axheard(ifp);
  292.         return 0;
  293.     }
  294.     for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
  295.         if(ifp->output != ax_output)
  296.             continue;    /* Not an ax.25 interface */
  297.         axheard(ifp);
  298.     }
  299.     return 0;
  300. }
  301.  
  302. static int
  303. doaxflush(argc,argv,p)
  304. int argc;
  305. char *argv[];
  306. void *p;
  307. {
  308.     struct iface *ifp;
  309.  
  310.     for(ifp = Ifaces;ifp != NULLIF;ifp = ifp->next){
  311.         if(ifp->output == ax_output)
  312.             axflush(ifp);
  313.     }
  314.     return 0;
  315. }
  316.  
  317. static char  * near
  318. pathtostr(cp)
  319. struct ax25_cb *cp;
  320. {
  321.  
  322.   char  *ap, *p;
  323.   static char buf[128];
  324.  
  325.   if (!cp->pathlen) return "*";
  326.   p = buf;
  327.   ap = cp->path + AXALEN;
  328.   if (!addreq(ap,cp->iface->hwaddr)) {
  329.     pax25(p, ap);
  330.     while (*p) p++;
  331.     *p++ = '-';
  332.     *p++ = '>';
  333.   }
  334.   pax25(p, cp->path);
  335.   while (*p) p++;
  336.   while (!(ap[6] & E)) {
  337.     ap += AXALEN;
  338.     *p++ = ',';
  339.     pax25(p, ap);
  340.     while (*p) p++;
  341.     if (ap[6] & REPEATED) *p++ = '*';
  342.   }
  343.   *p = '\0';
  344.   return buf;
  345. }
  346.  
  347. /* Dump one control block */
  348. void
  349. st_ax25(struct ax25_cb *cp) {
  350.   int i;
  351.  
  352.   tprintf("Path: %s\nIface: %s  State: %s  DAMA: %s\n",
  353.       pathtostr(cp),
  354.       cp->iface ? cp->iface->name : "???",
  355.       Ax25states[cp->state],
  356.       cp->dama ? "Yes" : "No");
  357.  
  358.   tprintf("Closed: %-5sPolling: %-5sREJsent: %-5sRNRsent: %-6sRNRrecv: ",
  359.       cp->closed  ? "Yes" : "No",
  360.       cp->polling ? "Yes" : "No",
  361.       cp->rejsent ? "Yes" : "No",
  362.       cp->rnrsent ? "Yes" : "No");
  363.  
  364.   if (cp->remotebusy)
  365.     tprintf("%ld sec", currtime - cp->remotebusy);
  366.   else
  367.     tputs("No");
  368.  
  369.   tprintf("\nCWind: %-6dRetry: %-7dUnack: %-7dSRT: %2ld sec    Mdev: %2ld sec\nT1: ",
  370.       cp->cwind,cp->retries,cp->unack,
  371.       cp->srt / 1000L,cp->mdev / 1000L);
  372.  
  373.   if (run_timer(&cp->t1))
  374.     tprintf("%ld",read_timer(&cp->t1) / 1000L);
  375.   else
  376.     tputs("-");
  377.   tprintf("/%ld sec  T2: ",dur_timer(&cp->t1) / 1000L);
  378.   if (run_timer(&cp->t2))
  379.     tprintf("%ld",read_timer(&cp->t2) / 1000L);
  380.   else
  381.     tputs("-");
  382.   tprintf("/%ld sec  T3: ",dur_timer(&cp->t2) / 1000L);
  383.   if (run_timer(&cp->t3))
  384.     tprintf("%ld",read_timer(&cp->t3) / 1000L);
  385.   else
  386.     tputs("-");
  387.   tprintf("/%ld sec  T4: ",dur_timer(&cp->t3) / 1000L);
  388.   if (run_timer(&cp->t4))
  389.     tprintf("%ld",read_timer(&cp->t4) / 1000L);
  390.   else
  391.     tputs("-");
  392.   tprintf("/%ld sec  T5: ",dur_timer(&cp->t4) / 1000L);
  393.   if (run_timer(&cp->t5))
  394.     tprintf("%ld",read_timer(&cp->t5) / 1000L);
  395.   else
  396.     tputs("-");
  397.   tprintf("/%ld sec\nT6: ",dur_timer(&cp->t5) / 1000L);
  398.   if (run_timer(&cp->t6) && cp->dama)
  399.     tprintf("%ld",read_timer(&cp->t6) / 1000L);
  400.   else
  401.     tputs("-");
  402.   tprintf("/%ld sec\n",dur_timer(&cp->t6) / 1000L);
  403.  
  404.   if(cp->rxq)
  405.     tprintf("Rcv queue: %d\n", len_p(cp->rxq));
  406.  
  407.   if (cp->reseq[0].bp || cp->reseq[1].bp ||
  408.     cp->reseq[2].bp || cp->reseq[3].bp ||
  409.     cp->reseq[4].bp || cp->reseq[5].bp ||
  410.     cp->reseq[6].bp || cp->reseq[7].bp) {
  411.     tputs("Reassembly queue:\n");
  412.     for (i = next_seq(cp->vr); i != cp->vr; i = next_seq(i))
  413.       if (cp->reseq[i].bp)
  414.     tprintf("           Seq %3d: %3d bytes\n",i,len_p(cp->reseq[i].bp));
  415.   }
  416.   if(cp->txq)
  417.     tprintf("Snd queue: %d\n", len_p(cp->txq));
  418.  
  419.   if (cp->rxasm) {
  420.     struct mbuf *bp;
  421.     tputs("Resend queue:\n");
  422.     for (i = 0, bp = cp->rxasm; bp; i++, bp = bp->anext)
  423.       tprintf("           Seq %3d: %3d bytes\n",(cp->vs - cp->unack + i) & 7, len_p(bp));
  424. }
  425. return;
  426. }
  427.  
  428. /* Display AX.25 link level control blocks */
  429. static int
  430. doaxstat(argc,argv,p)
  431. int argc;
  432. char *argv[];
  433. void *p;
  434. {
  435.     struct ax25_cb *axp;
  436.     char tmp[AXBUF];
  437.  
  438.     if(argc < 2){
  439.         tputs("&AXCB    Rcv-Q Snd-Q  Local     Remote    Iface     State\n");
  440.         for(axp = Ax25_cb; axp != NULLAX25; axp = axp->next){
  441.             if(axp->state == LISTEN) {
  442.                 tprintf("%8lx%54s\n",ptol(axp),"Listen (S)");
  443.                 continue;
  444.             }
  445.             tprintf("%8lx%6d%6d  %-10s",
  446.                 ptol(axp),len_p(axp->rxq),len_p(axp->txq),pax25(tmp,axp->path + AXALEN));
  447.             tprintf("%-10s%-10s%s\n",
  448.                 pax25(tmp,axp->path),
  449.                 axp->iface ? axp->iface->name : "???",
  450.                 Ax25states[axp->state]);
  451.         }
  452.         return 0;
  453.     }
  454.     axp = (struct ax25_cb *)ltop(htol(argv[1]));
  455.     if(!ax25val(axp)){
  456.         tputs(Notval);
  457.         return 1;
  458.     }
  459.     if(axp->state != LISTEN) {
  460.         tprintf("&AXCB %lx  &Peer %lx\n",ptol(axp),ptol(axp->peer));
  461.         st_ax25(axp);
  462.     }
  463.     return 0;
  464. }
  465.  
  466. /* Display or change our AX.25 address */
  467. static int
  468. domycall(argc,argv,p)
  469. int argc;
  470. char *argv[];
  471. void *p;
  472. {
  473.     char tmp[AXBUF];
  474.  
  475.     if(argc < 2){
  476.         tprintf("%s\n",pax25(tmp,Mycall));
  477.     } else {
  478.         if(setcall(Mycall,argv[1]) == -1)
  479.             return -1;
  480.     }
  481.     return 0;
  482. }
  483.  
  484. /* Control AX.25 digipeating */
  485. static int
  486. dodigipeat(argc,argv,p)
  487. int argc;
  488. char *argv[];
  489. void *p;
  490. {
  491.     struct iface *ifp;
  492.  
  493.     if((ifp = cmp_if(argv[1])) != NULLIF)
  494.         return setintrc(&ifp->flags->digipeat,"Digipeat",--argc,++argv,0,2);
  495.     return -1;
  496. }
  497.  
  498. static int
  499. dot1(argc,argv,p)
  500. int argc;
  501. char *argv[];
  502. void *p;
  503. {
  504.     struct iface *ifp;
  505.  
  506.     if((ifp = cmp_if(argv[1])) != NULLIF)
  507.         return setintrc(&ifp->flags->t1init,"T1init",--argc,++argv,3,30);
  508.     return -1;
  509. }
  510.  
  511. static int
  512. dot2(argc,argv,p)
  513. int argc;
  514. char *argv[];
  515. void *p;
  516. {
  517.     struct iface *ifp;
  518.  
  519.     if((ifp = cmp_if(argv[1])) != NULLIF)
  520.         return setintrc(&ifp->flags->t2init,"T2init",--argc,++argv,0,ifp->flags->t1init/2);
  521.     return -1;
  522. }
  523.  
  524. static int
  525. dot3(argc,argv,p)
  526. int argc;
  527. char *argv[];
  528. void *p;
  529. {
  530.     struct iface *ifp;
  531.  
  532.     if((ifp = cmp_if(argv[1])) != NULLIF)
  533.         return setintrc(&ifp->flags->t3init,"T3init",--argc,++argv,0,3600);
  534.     return -1;
  535. }
  536.  
  537. static int
  538. dot4(argc,argv,p)
  539. int argc;
  540. char *argv[];
  541. void *p;
  542. {
  543.     struct iface *ifp;
  544.  
  545.     if((ifp = cmp_if(argv[1])) != NULLIF)
  546.         return setintrc(&ifp->flags->t4init,"T4init",--argc,++argv,ifp->flags->t1init*2,ifp->flags->t1init*20);
  547.     return -1;
  548. }
  549.  
  550. static int
  551. dot5(argc,argv,p)
  552. int argc;
  553. char *argv[];
  554. void *p;
  555. {
  556.   struct iface *ifp;
  557.  
  558.   if((ifp = cmp_if(argv[1])) != NULLIF)
  559.     return setintrc(&ifp->flags->t5init,"T5init",--argc,++argv,0,ifp->flags->t2init-1);
  560.   return -1;
  561. }
  562.  
  563. static int
  564. dot6(int argc,char *argv[],void *p) {
  565.   struct iface *ifp;
  566.  
  567.   if((ifp = cmp_if(argv[1])) != NULLIF)
  568.     return setintrc(&ifp->flags->t6init,"T6init",--argc,++argv,180,ifp->flags->t3init-1);
  569.   return -1;
  570. }
  571.  
  572.  
  573. /* Set retry limit count */
  574. static int
  575. doretries(argc,argv,p)
  576. int argc;
  577. char *argv[];
  578. void *p;
  579. {
  580.     struct iface *ifp;
  581.  
  582.     if((ifp = cmp_if(argv[1])) != NULLIF)
  583.         return setintrc(&ifp->flags->retries,"Retries",--argc,++argv,0,50);
  584.     return -1;
  585. }
  586.  
  587. /* Force a retransmission */
  588. static int
  589. doaxkick(argc,argv,p)
  590. int argc;
  591. char *argv[];
  592. void *p;
  593. {
  594.     struct ax25_cb *axp = (struct ax25_cb *)ltop(htol(argv[1]));
  595.  
  596.     if(!ax25val(axp)){
  597.         tputs(Notval);
  598.         return 1;
  599.     }
  600.     kick_ax25(axp);
  601.     return 0;
  602. }
  603.  
  604. /* Set maximum number of frames that will be allowed in flight */
  605. static int
  606. domaxframe(argc,argv,p)
  607. int argc;
  608. char *argv[];
  609. void *p;
  610. {
  611.     struct iface *ifp;
  612.  
  613.     if((ifp = cmp_if(argv[1])) != NULLIF)
  614.         return setintrc(&ifp->flags->maxframe,"Maxframe",--argc,++argv,1,7);
  615.     return -1;
  616. }
  617.  
  618. static int
  619. domaxheard(argc,argv,p)
  620. int argc;
  621. char *argv[];
  622. void *p;
  623. {
  624.     struct iface *ifp;
  625.  
  626.     if((ifp = cmp_if(argv[1])) != NULLIF) {
  627.         if(argc < 3)
  628.             return(setint(&ifp->Hmax,"Maxheard",--argc,++argv));
  629.         else
  630.             return(maxheard(ifp,atoi(argv[2])));
  631.     }
  632.     return -1;
  633. }
  634.  
  635. static int
  636. dot3disc(argc,argv,p)
  637. int argc;
  638. char *argv[];
  639. void *p;
  640. {
  641.     struct iface *ifp;
  642.  
  643.     if((ifp = cmp_if(argv[1])) != NULLIF)
  644.         return setbool(&ifp->flags->t3disc,"T3disc",--argc,++argv);
  645.     return -1;
  646. }
  647.  
  648. /* Set maximum length of I-frame data field */
  649. static int
  650. dopaclen(argc,argv,p)
  651. int argc;
  652. char *argv[];
  653. void *p;
  654. {
  655.     struct iface *ifp;
  656.  
  657.     if((ifp = cmp_if(argv[1])) != NULLIF)
  658.         return setintrc(&ifp->flags->paclen,"Paclen",--argc,++argv,1,2048);
  659.     return -1;
  660. }
  661.  
  662. /* Set size of I-frame above which polls will be sent after a timeout */
  663. static int
  664. dopthresh(argc,argv,p)
  665. int argc;
  666. char *argv[];
  667. void *p;
  668. {
  669.     struct iface *ifp;
  670.  
  671.     if((ifp = cmp_if(argv[1])) != NULLIF)
  672.         return setintrc(&ifp->flags->pthresh,"Pthresh",--argc,++argv,0,ifp->flags->paclen);
  673.     return -1;
  674. }
  675.  
  676. /* Set high water mark on receive queue that triggers RNR */
  677. static int
  678. doaxwindow(argc,argv,p)
  679. int argc;
  680. char *argv[];
  681. void *p;
  682. {
  683.     struct iface *ifp;
  684.  
  685.     if((ifp = cmp_if(argv[1])) != NULLIF)
  686.         return setintrc(&ifp->flags->axwindow,"Axwindow",
  687.             --argc,++argv,ifp->flags->paclen/2,ifp->flags->paclen*8);
  688.     return -1;
  689. }
  690. /* End of ax25 subcommands */
  691.  
  692. /* Initiate interactive AX.25 connect to remote station */
  693. int
  694. doconnect(argc, argv, p)
  695. int  argc;
  696. char  *argv[];
  697. void *p;
  698. {
  699.   char  *ap, tmp[AXBUF], path[10*AXALEN];
  700.   struct session *sp;
  701.   struct iface *ifp = NULLIF;
  702.   struct sockaddr_ax fsocket;
  703.   struct ax25_cb axp;
  704.  
  705.   argc--;
  706.   argv++;
  707.  
  708.   if((ifp = if_lookup(*argv)) != NULLIF) {
  709.     if(ifp->output != ax_output) {
  710.       tprintf(Badax,*argv);
  711.       return 1;
  712.     }
  713.     argc--;
  714.     argv++;
  715.   }
  716.   for (ap = path; argc > 0; argc--, argv++) {
  717.     if (!strncmp("via", *argv, strlen(*argv))) continue;
  718.     if (ap >= path + sizeof(path)) {
  719.       tputs("Max 8 digis\n");
  720.       return 1;
  721.     }
  722.     if (setcall(ap, *argv)) {
  723.       tprintf("Invalid call %s\n", *argv);
  724.       return 1;
  725.     }
  726.     ap[ALEN] &= ~E;
  727.  
  728.     if (ap == path) {
  729.       ap += AXALEN;
  730.       addrcp(ap,Mycall);
  731.       ap[ALEN] &= ~E;
  732.     }
  733.     ap += AXALEN;
  734.   }
  735.   if (ap < path + 2 * AXALEN) {
  736.     tputs("Missing call\n");
  737.     return 1;
  738.   }
  739.   ap[-1] |= E;
  740.  
  741.   memset(&axp,0,sizeof(struct ax25_cb));
  742.  
  743.   build_path(&axp,ifp,path,0,0);
  744.  
  745.   if(!axp.iface) {
  746.     tputs("No specified iface\n");
  747.     return 1;
  748.   }
  749.  
  750.   addrcp(axp.path + AXALEN,axp.iface->hwaddr);
  751.   axroute_add(&axp,0);
  752.  
  753.   /* Allocate a session descriptor */
  754.   if((sp = newsession(pax25(tmp,axp.path),AX25TNC,1,1)) == NULLSESSION){
  755.     tputs(Nosess);
  756.     return 1;
  757.   }
  758.  
  759.   if((sp->s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
  760.     tputs(Nosocket);
  761.     goto quit;
  762.   }
  763.  
  764.   fsocket.sax_family = AF_AX25;
  765.   memcpy(fsocket.ax25_addr,axp.path,AXALEN);
  766.   memcpy(fsocket.iface,axp.iface->name,ILEN);
  767.   if(!(tel_connect(sp, (char *)&fsocket, sizeof(struct sockaddr_ax))))
  768.     return 0;
  769. quit:
  770.   keywait(NULLCHAR,1);
  771.   freesession(sp);
  772.   return 1;
  773. }
  774.  
  775. static int
  776. dorouteadd(argc, argv, p)
  777. int  argc;
  778. char  *argv[];
  779. void *p;
  780. {
  781.  
  782.   char  *ap;
  783.   int  perm;
  784.   struct ax25_cb cb;
  785.  
  786.   argc--;
  787.   argv++;
  788.  
  789.   if ((perm = !strcmp(*argv, "permanent")) != 0) {
  790.     argc--;
  791.     argv++;
  792.   }
  793.   if ((cb.iface = cmp_if(*argv)) == NULLIF)
  794.     return 1;
  795.  
  796.   argc--;
  797.   argv++;
  798.  
  799.   if (!strcmp(*argv,"default")) {
  800.     axroute_default_ifp = cb.iface;
  801.     return 0;
  802.   }
  803.   for (ap = cb.path; argc > 0; argc--, argv++) {
  804.     if (!strncmp("via", *argv, strlen(*argv)))
  805.       continue;
  806.     if (ap >= cb.path + sizeof(cb.path)) {
  807.       tputs("Max 8 digis\n");
  808.       return 1;
  809.     }
  810.     if (setcall(ap, *argv)) {
  811.       tprintf("Invalid call %s\n", *argv);
  812.       return 1;
  813.     }
  814.     if (ap == cb.path) {
  815.       ap += AXALEN;
  816.       addrcp(ap,cb.iface->hwaddr);
  817.     }
  818.     ap += AXALEN;
  819.   }
  820.   if (ap < cb.path + 2 * AXALEN) {
  821.     tputs("Missing call\n");
  822.     return 1;
  823.   }
  824.   ap[-1] |= E;
  825.   cb.pathlen = (int)(ap - cb.path);
  826.   axroute_add(&cb, perm);
  827.   return 0;
  828. }
  829.  
  830. #include "smtp.h"        /* for 'Months' */
  831.  
  832. void
  833. doroutelistentry(rp)
  834. struct axroute_tab *rp;
  835. {
  836.   char  *cp, *buf = mxallocw(10*AXBUF);
  837.   int i, n, perm = rp->perm;
  838.   struct axroute_tab *rp_stack[20];
  839.   struct iface *ifp;
  840.   struct tm *tm = gmtime(&rp->time);
  841.  
  842.   pax25(cp = buf, (char *) &rp->call);
  843.  
  844.   for (n = 0; rp; rp = rp->digi) {
  845.     rp_stack[++n] = rp;
  846.     ifp = rp->ifp;
  847.   }
  848.   for (i = n; i > 1; i--) {
  849.     strcat(cp, i == n ? " via " : ",");
  850.     while (*cp) cp++;
  851.     pax25(cp, (char *) &(rp_stack[i]->call));
  852.   }
  853.   tprintf("%2d-%.3s  %02d:%02d  %-9s  %c %s\n",
  854.     tm->tm_mday,
  855.     Months[tm->tm_mon],
  856. /*
  857.     "JanFebMarAprMayJunJulAugSepOctNovDec" + 3 * tm->tm_mon,
  858. */
  859.     tm->tm_hour,
  860.     tm->tm_min,
  861.     ifp ? ifp->name : "???",
  862.     perm ? '*' : ' ',
  863.     buf);
  864.   xfree(buf);
  865. }
  866.  
  867. static int
  868. doroutelist(argc, argv, p)
  869. int  argc;
  870. char  *argv[];
  871. void *p;
  872. {
  873.   int  i;
  874.   struct ax25_addr call;
  875.   struct axroute_tab *rp;
  876.   char tmp[AXBUF];
  877.  
  878.   tputs("Date    GMT    Interface  P Path\n");
  879.   if (argc < 2) {
  880.     for (i = 0; i < AXROUTESIZE; i++)
  881.       for (rp = axroute_tab[i]; rp; rp = rp->next)
  882.         doroutelistentry(rp);
  883.   } else {
  884.     for (i = 1; i < argc; i++)
  885.       if (setcall((char *) &call,argv[i]) || (rp = axroute_tabptr(&call,0)) == 0)
  886.         tprintf("*** no route to %s\n",pax25(tmp,(char *) &call));
  887.       else
  888.         doroutelistentry(rp);
  889.   }
  890.   return 0;
  891. }
  892.  
  893. static int
  894. doroutehold(argc, argv, p)
  895. int argc;
  896. char *argv[];
  897. void *p;
  898. {
  899.     int16 holdtime = (int16)(Axholdtime / (60L*60*24));
  900.  
  901.     if(setintrc(&holdtime,"Holdtime (days)",argc,argv,1,120) == 0) {
  902.         Axholdtime = (int32)(holdtime * 60L*60*24);
  903.         return 0;
  904.     }
  905.     return 1;
  906. }
  907.  
  908. static int
  909. doroutestat(argc, argv, p)
  910. int  argc;
  911. char  *argv[];
  912. void *p;
  913. {
  914.   struct ifptable_t {
  915.     struct iface *ifp;
  916.     int count;
  917.   } ;
  918.  
  919.   int  i, dev, total;
  920.   struct axroute_tab *rp, *dp;
  921.   struct iface *ifp;
  922.   struct ifptable_t ifptable[ASY_MAX
  923. #ifdef DRSI
  924.                          + DRMAX
  925. #endif
  926. #ifdef SCC
  927.                                      + MAXSCC
  928. #endif
  929. #ifdef VANESSA
  930.                                               + VAN_MAX
  931. #endif
  932. #ifdef AXIP
  933.                                                         + NAX25
  934. #endif
  935.                                                                ];
  936.   memset(ifptable,0,sizeof(ifptable));
  937.  
  938.   for (ifp = Ifaces; ifp; ifp = ifp->next)
  939.     if (ifp->output == ax_output)
  940.       ifptable[ifp->niface].ifp = ifp;
  941.  
  942.   for (i = 0; i < AXROUTESIZE; i++) {
  943.     for (rp = axroute_tab[i]; rp; rp = rp->next) {
  944.       for (dp = rp; dp->digi; dp = dp->digi) ;
  945.       if (dp->ifp)
  946.         ifptable[dp->ifp->niface].count++;
  947.     }
  948.   }
  949.   tputs("Interface  Count\n");
  950.   for (total = 0, dev = 0; dev < Niface; dev++) {
  951.     if(ifptable[dev].count /*|| ifptable[dev].ifp == axroute_default_ifp*/) {
  952.       tprintf("%c %-7s  %5d\n",
  953.         ifptable[dev].ifp == axroute_default_ifp ? '*' : ' ',
  954.         ifptable[dev].ifp->name,
  955.         ifptable[dev].count);
  956.       total += ifptable[dev].count;
  957.     }
  958.   }
  959.   tprintf("  total    %5d\n", total);
  960.   return 0;
  961. }
  962.  
  963. /* Display and modify AX.25 routing table */
  964. static int
  965. doaxroute(argc, argv, p)
  966. int  argc;
  967. char  *argv[];
  968. void *p;
  969. {
  970.   struct cmds routecmds[] = {
  971.     "add",  dorouteadd,  0, 3, "ax25 route add [permanent] <iface> <path>",
  972.     "hold", doroutehold, 0, 0, NULLCHAR,
  973.     "list", doroutelist, 0, 0, NULLCHAR,
  974.     "stat", doroutestat, 0, 0, NULLCHAR,
  975.     NULLCHAR, NULLFP,    0, 0, NULLCHAR
  976.   };
  977.  
  978.   if (argc >= 2)
  979.     return subcmd(routecmds, argc, argv, p);
  980.   doroutestat(argc, argv, p);
  981.   return 0;
  982. }
  983.  
  984. /* Multiplexer for top-level ax25 command */
  985. int
  986. doax25(argc,argv,p)
  987. int argc;
  988. char *argv[];
  989. void *p;
  990. {
  991.     struct cmds Axcmds[] = {
  992.         "bc",            dobc,        0, 2, "ax25 bc <iface>",
  993.         "bcinterval",     dobcint,    0, 0, NULLCHAR,
  994.         "bctext",        dobctext,    0, 0, NULLCHAR,
  995.         "bud",            dobud,        0, 2, "ax25 bud <call>",
  996.         "close",        doaxclose,    0, 2, "ax25 close <axcb>",
  997.         "digipeat",        dodigipeat,    0, 2, "ax25 digipeat <iface>",
  998.         "flush",        doaxflush,    0, 0, NULLCHAR,
  999.         "heard",        doaxheard,    0, 0, NULLCHAR,
  1000.         "kick",            doaxkick,    0, 2, "ax25 kick <axcb>",
  1001.         "maxframe",        domaxframe,    0, 2, "ax25 maxframe <iface>",
  1002.         "maxheard",        domaxheard, 0, 2, "ax25 maxheard <iface>",
  1003.         "mycall",        domycall,    0, 0, NULLCHAR,
  1004.         "paclen",        dopaclen,    0, 2, "ax25 paclen <iface>",
  1005.         "pthresh",        dopthresh,    0, 0, NULLCHAR,
  1006.         "reset",        doaxreset,    0, 2, "ax25 reset <axcb>",
  1007.         "retry",        doretries,    0, 2, "ax25 retry <iface>",
  1008.         "route",        doaxroute,    0, 0, NULLCHAR,
  1009.         "status",        doaxstat,    0, 0, NULLCHAR,
  1010.         "t1",            dot1,        0, 2, "ax25 t1 <iface>",
  1011.         "t2",            dot2,        0, 2, "ax25 t2 <iface>",
  1012.         "t3",            dot3,        0, 2, "ax25 t3 <iface>",
  1013.         "t3disc",        dot3disc,    0, 2, "ax25 t3disc <iface>",
  1014.         "t4",            dot4,        0, 2, "ax25 t4 <iface>",
  1015.         "t5",            dot5,        0, 2, "ax25 t5 <iface>",
  1016.         "t6",            dot6,        0, 2, "ax25 t6 <iface>",
  1017.         "window",        doaxwindow,    0, 2, "ax25 window <iface>",
  1018.         NULLCHAR,
  1019.     };
  1020.     return subcmd(Axcmds,argc,argv,p);
  1021. }
  1022.  
  1023.